﻿using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using ufida.u9.ait.openbp;
using UFIDA.U9.AIT.OpenAPIBE;
using UFIDA.U9.Base;
using UFIDA.U9.Base.Currency;
using UFIDA.U9.Base.Profile;
using UFIDA.U9.Base.PropertyTypes;
using UFIDA.U9.Base.UOM;
using UFIDA.U9.Base.UserRole;
using UFIDA.U9.CBO.Pub.Controller;
using UFIDA.U9.CBO.PubSV.Helper;
using UFIDA.U9.CBO.SCM.Item;
using UFIDA.U9.InvDoc;
using UFSoft.UBF.Business;
using UFSoft.UBF.PL;
using UFSoft.UBF.Transactions;
using UFSoft.UBF.Util.Context;
using UFSoft.UBF.Util.DataAccess;
using UFSoft.UBF.View.Query;
using static UFIDA.U9.CBO.PubSV.Helper.CBOCommonHelper;
using static UFIDA.U9.PPR.PurPriceList.PurPriceLine;

namespace ufida.u9.ait.openapi.utils
{
    /// <summary>
    /// U9工具类
    /// </summary>
    public class U9Utils
    {
        const string filepath = "RestServices/ufida.u9.ait.openapi.IHelloSV.svc";
        static DateTime fileTime = DateTime.MinValue;
        const int days = 62;
        //是否做有效性检查
        static readonly bool IsCheck = false;

        static U9Utils()
        {
            U9Utils.fileTime = FileUtils.GetFileTime(System.IO.Path.Combine(U9Utils.GetU9Dir(), filepath));
        }

        /// <summary>
        /// 获取单位之间的转换率
        /// </summary>
        /// <param name="fromUOM"></param>
        /// <param name="toUOM"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        public static decimal GetUom2Rate(UOM fromUOM, UOM toUOM, ItemMaster item)
        {
            if (fromUOM.ID == toUOM.ID)
                return 1;
            else
                return GetUOMRateHelper.GetUomToUomRate(fromUOM.Key, toUOM.Key, item.Key);
        }

        /// <summary>
        /// U9弱实体查询方式
        /// </summary>
        /// <param name="entityName">实体全名</param>
        /// <param name="opath">where条件</param>
        /// <returns>实体集合</returns>
        public static IList EntityQuery(string entityName,string opath)
        {
            EntityQuery qry = new EntityQuery(entityName);
            IList list = qry.FindAll(opath);
            return list;
        }
        /// <summary>
        /// U9弱实体查询方式,基于单号查询
        /// </summary>
        /// <param name="entityName">实体全名</param>
        /// <param name="docno">单号</param>
        /// <returns></returns>
        public static BusinessEntity DocQuery(string entityName, string docno)
        {
            string opath = $"DocNo='{docno}'";
            IList list = EntityQuery(entityName, opath);

            if (list == null || list.Count == 0) return null;
            return (BusinessEntity)list[0];
        }

        /// <summary>
        /// 通过SQL获取动态集合
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        public static List<Dictionary<string, object>> RunSQL(string sql)
        {
            LogUtils.Log($"DB通用查询,sql: {sql}");

            DataSet ds = new DataSet();
            DataAccessor.RunSQL(DataAccessor.GetConn(), sql, null,out ds);
            List<Dictionary<string, object>> ret = DS2List(ds);
            return ret;
        }

        /// <summary>
        /// 运行SQL查询XX表数据
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="path">查询条件</param>
        /// <param name="order">排序条件</param>
        /// <returns></returns>
        public static List<Dictionary<string, object>> RunSQL(string tableName,string path,string order)
        {
            string sql=$"select * from {tableName} where 1=1";
            if (!String.IsNullOrEmpty(path))
            {
                if(path.Trim().StartsWith("and", StringComparison.OrdinalIgnoreCase))
                    sql += $" {path}";
                else
                    sql += $" and {path}";
            }
            if (!String.IsNullOrEmpty(order))
            {
                if (order.Trim().StartsWith("order by", StringComparison.OrdinalIgnoreCase))
                    sql += $" {order}";
                else
                    sql += $" order by {order}";
            }
            return RunSQL(sql);
        }

        /// <summary>
        /// 通过OQL获取动态集合
        /// </summary>
        /// <param name="oql"></param>
        /// <returns></returns>
        public static List<Dictionary<string,object>> RunOql(string oql)
        {
            EntityViewQuery viewQry = new EntityViewQuery();
            ObjectQuery oq = viewQry.CreateQuery(oql);
            DataSet ds = viewQry.ExecuteDataSet(oq, null);
            List<Dictionary<string, object>> ret = DS2List(ds);
            return ret;
        }

        private static List<Dictionary<string, object>> DS2List(DataSet ds)
        {
            // 安全检查：DataSet 或 Tables 为 null
            if (ds?.Tables == null || ds.Tables.Count == 0)
                return new List<Dictionary<string, object>>();
            var table = ds.Tables[0];
            if (table.Rows.Count == 0)
                return new List<Dictionary<string, object>>();

            var result = new List<Dictionary<string, object>>(table.Rows.Count); // 预分配容量提升性能
            foreach (DataRow row in table.Rows)
            {
                var dict = new Dictionary<string, object>(table.Columns.Count); // 预分配容量
                foreach (DataColumn col in table.Columns)
                {
                    object value = row[col];
                    // 将 DBNull 转换为 null，避免后续 JSON 序列化等问题
                    dict[col.ColumnName] = value == DBNull.Value ? null : value;
                }
                result.Add(dict);
            }
            return result;
        }

        /// <summary>
        /// 依据参数编码,获取U9参数
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public static string GetU9SysParam(String code)
        {
            Profile profile = Profile.Finder.Find($"Code='{code}'");
            if (profile == null || profile.ProfileValues == null || profile.ProfileValues.Count == 0)
                return "";
            return profile.ProfileValues[0].Value;
        }

        /// <summary>
        /// 将DTO字段赋值到BE字段
        /// DTO中的编码字段(CommonArchiveDataDTO对象)转换为ID
        /// 参考代码 BatchCreateCustomerByDTOSV
        /// </summary>
        /// <typeparam name="D">DTO类型</typeparam>
        /// <typeparam name="B">BE类型</typeparam>
        /// <param name="dto">DTO</param>
        /// <param name="be">BE</param>
        /// <param name="setValue"></param>
        public static void DtoToEntity<D, B>(D dto, B be, SetValue<D, B> setValue) where D : DTOBase where B : BusinessEntity
        {
            CBOCommonHelper.DtoToEntity(dto, be, setValue);
        }
        /// <summary>
        /// 清除所有实体缓存
        /// 下述方法只清除线程级缓存
        /// </summary>
        public static void ClearCache()
        {
            // 清除所有实体缓存
            UFSoft.UBF.PL.Engine.Cache.PLCacheManager.DataCache.FlushCache();
            UFSoft.UBF.PL.Engine.Cache.PLCacheManager.ObjectCache.FlushCache();
        }

        /// <summary>
        /// 清除单个实体缓存
        /// 这个好像不起作用,不推荐使用
        /// </summary>
        /// <param name="key">单据Key</param>
        [Obsolete("方法好像不起作用，建议使用ClearCache()代替。")]
        public static void ClearCache(IWeakObjectKey key)
        {
            // 清除单个实体缓存
            UFSoft.UBF.PL.Engine.Cache.PLCacheManager.DataCache.RemoveValue(key);
            UFSoft.UBF.PL.Engine.Cache.PLCacheManager.ObjectCache.RemoveObject(key);
        }

        /// <summary>
        /// 金额精度计算
        /// </summary>
        /// <param name="curr"></param>
        /// <param name="mny"></param>
        /// <returns></returns>
        public static decimal GetRoundMoney(Currency curr,decimal mny)
        {
            UFIDA.U9.Base.PropertyTypes.Round round = curr.MoneyRound;
            return round.GetRoundValue(mny);
        }
        public static decimal GetRoundPrice(Currency curr,decimal price)
        {
            UFIDA.U9.Base.PropertyTypes.Round round = curr.PriceRound;
            return round.GetRoundValue(price);
        }

        /// <summary>
        /// 获取U9当前目录,比如:D:\yonyou\U9CE\Portal
        /// </summary>
        /// <returns></returns>
        public static String GetU9Dir()
        {
            return AppDomain.CurrentDomain.BaseDirectory;
        }

        /// <summary>
        /// 设置当前上下文
        /// </summary>
        /// <param name="context"></param>
        public static void SetContext(ContextDTO context)
        {
            context.WriteToContext();
        }
        public static void SetContext(ContextDTOData context)
        {
            ContextDTO context1 = new ContextDTO();
            context1.FromEntityData(context);
            context1.WriteToContext();
        }

        //创建调用上下文
        public static ContextDTOData CreateContext()
        {

            User user = User.Finder.FindByID(Context.LoginUserID);
            if(user == null)
            {
                throw new Exception("查找用户失败!");
            }

            ContextDTOData retdto = new ContextDTOData
            {
                CultureName = PlatformContext.Current.Culture,
                EntCode = PlatformContext.Current.EnterpriseID,
                OrgCode = Context.LoginOrg.Code,
                OrgID = Context.LoginOrg.ID,
                UserCode = user.Code,//这里传入用户编码
                UserID = Convert.ToInt64(Context.LoginUserID)
            };
            return retdto;
        }

        public static bool IsValid()
        {
            if (IsCheck == false)
                return true;
            else if (fileTime.AddDays(days) > DateTime.Now)
                return true;
            else
                return false;
        }
        /// <summary>
        /// 获取DTO中的单号DocNo/编码Code的值
        /// 只会获取集合中的第一条数据
        /// </summary>
        /// <param name="data">接收的DTO集合</param>
        /// <returns>单号/编码的值</returns>
        private static string GetCode(object data)
        {
            string code = "";
            if(data is IList)
            {
                IList list=((IList)data);
                if(list.Count > 0)
                {
                    object data1=list[0];
                    try
                    {
                        code = DTOUtils.GetDocNo(data1);
                    }
                    catch (Exception ex)
                    {
                        code = "";
                    }
                }
            }
            return code;
        }
        /// <summary>
        /// 数据库日志
        /// 用于U9 API日志记录
        /// 不启用事务
        /// </summary>
        /// <param name="method"></param>
        /// <param name="indata"></param>
        /// <param name="retdto"></param>
        public static void DBLog(object method, object indata, ResultDTOData retdto)
        {
            //记录日志,不考虑外部事务
            using (UBFTransactionScope logScope = new UBFTransactionScope(TransactionOption.NotSupported))
            {
                using (ISession session = Session.Open())
                {
                    AITLog logbe = AITLog.Create();
                    logbe.Code = GetCode(indata);
                    logbe.Name = method.GetType().Name;
                    if (indata != null)
                    {
                        //添加context部分
                        ContextDTOData contextDTOData = CreateContext();
                        Dictionary<String, Object> context = new Dictionary<string, object>();
                        context.Add("CultureName", contextDTOData.CultureName);
                        context.Add("EntCode", contextDTOData.EntCode);
                        context.Add("OrgCode", contextDTOData.OrgCode);
                        context.Add("UserCode", contextDTOData.UserCode);

                        //构造传入参数
                        Dictionary<String, Object> inparm = new Dictionary<string, object>();
                        inparm.Add("context", context);
                        inparm.Add("data", indata);
                        string json = JSONUtils.toJSONStr(inparm);
                        logbe.InParm = json;
                    }
                    if (retdto != null)
                    {
                        string json = JSONUtils.toJSONStr(retdto);
                        logbe.OutParm = json;
                    }
                    logbe.RetCode = retdto.Code;
                    logbe.RetMsg = retdto.Msg;

                    session.Commit();
                }
                logScope.Commit();
            }

        }
        /// <summary>
        /// 调用外部接口日志记录
        /// 单独BP,启用事务Require New
        /// </summary>
        /// <param name="url">外部url</param>
        /// <param name="method">方法:get,post</param>
        /// <param name="body"></param>
        /// <param name="retdata"></param>
        /// <param name="retcode">post返回码</param>
        /// <param name="retmsg">错误消息</param>
        public static void DBLog(string url,string method,string body,string retdata,int retcode,string retmsg)
        {
            //在BP中启用事务RN(Require New),确保日志能够保存上
            AITLogSaveBP bp=new AITLogSaveBP();
            bp.Log = new AITLogDTO()
            {
                Code="wbdy",
                Name="外部调用",
                Method = method,
                InParm = body,
                OutParm = retdata,
                Retcode = retcode,
                Retmsg = retmsg,
                Url = url,
                StartTime = DateTime.Now,
                EndTime = DateTime.Now,
            };
            bp.Do();
        }

        /// <summary>
        /// 依据传入 EffectiveDTOData ,构造实体 Effective
        /// </summary>
        /// <param name="dto">EffectiveDTOData 可以为空</param>
        /// <returns>Effective</returns>
        internal static Effective GetEffective(EffectiveDTOData dto)
        {
            Effective ret = new Effective();
            //构造默认值
            ret.IsEffective = true;
            ret.EffectiveDate = DateTime.Now;
            ret.DisableDate = DateTime.MaxValue;
            if (dto != null)
            {
                //依据传入dto赋值
                ret.IsEffective = dto.IsEffective;
                if(!string.IsNullOrEmpty(dto.EffectiveDate))
                {
                    ret.EffectiveDate = DateTime.Parse(dto.EffectiveDate);
                }
                if (!string.IsNullOrEmpty(dto.DisableDate))
                {
                    ret.DisableDate = DateTime.Parse(dto.DisableDate);
                }
            }

            return ret;
        }
    }
}
